package com.wsoft.bpm.service;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.wsoft.bpm.entity.ActProcessMappingEntity;
import com.wsoft.bpm.enums.ApproveStatus;
import com.wsoft.bpm.mapper.BpmActivitiMapper;
import com.wsoft.bpm.service.impl.DefaultActivityCallAbleImpl;
import com.wsoft.core.exception.Asserts;
import org.activiti.engine.HistoryService;
import org.activiti.engine.history.HistoricProcessInstance;

import java.util.Map;

/**
 * 工作流回调接口
 *
 * @Author zhonglj
 * @Date 2024-10-09 8:52
 */
public interface ActivityCallAble {
    /**
     * 终止-工作流自动回调
     *
     * @param processDefKey
     * @param processInstanceId 流程实例id
     * @param businessKey
     * @author zhonglj
     * @date 2024-10-09 9:01
     **/
    default void callTerminate(String processDefKey, String processInstanceId, String businessKey) {
        businessKey = getBusinessKey(processInstanceId, businessKey);
        updateApproveStatus(processInstanceId, businessKey, ApproveStatus.TERMINATE);
        terminate(processDefKey, processInstanceId, businessKey);
    }


    /**
     * 终止-业务逻辑覆盖
     *
     * @param processDefKey
     * @param processInstanceId 流程实例id
     * @param businessKey
     * @author zhonglj
     * @date 2024-10-09 9:01
     **/
    default void terminate(String processDefKey, String processInstanceId, String businessKey) {
    }

    /**
     * 完成-工作流自动回调
     *
     * @param processDefKey
     * @param processInstanceId 流程实例id
     * @param businessKey
     * @author zhonglj
     * @date 2024-10-09 9:01
     **/
    default void callComplete(String processDefKey, String processInstanceId, String businessKey) {
        businessKey = getBusinessKey(processInstanceId, businessKey);
        updateApproveStatus(processInstanceId, businessKey, ApproveStatus.APPROVED);
        complete(processDefKey, processInstanceId, businessKey);
    }


    /**
     * 完成-业务逻辑覆盖
     *
     * @param processDefKey
     * @param processInstanceId 流程实例id
     * @param businessKey
     * @author zhonglj
     * @date 2024-10-09 9:01
     **/
    default void complete(String processDefKey, String processInstanceId, String businessKey) {
    }


    /**
     * 退回至提交人-工作流自动回调
     *
     * @param processDefKey
     * @param processInstanceId 流程实例id
     * @param businessKey
     * @author zhonglj
     * @date 2024-10-09 9:01
     **/
    default void callBack(String processDefKey, String processInstanceId, String businessKey) {
        businessKey = getBusinessKey(processInstanceId, businessKey);
        updateApproveStatus(processInstanceId, businessKey, ApproveStatus.BACK);
        back(processDefKey, processInstanceId, businessKey);
    }

    /**
     * 退回至提交人-业务逻辑覆盖
     *
     * @param processDefKey
     * @param processInstanceId 流程实例id
     * @param businessKey
     * @author zhonglj
     * @date 2024-10-09 9:01
     **/
    default void back(String processDefKey, String processInstanceId, String businessKey) {
    }

    /**
     * 驳回至提交人-工作流自动回调
     *
     * @param processDefKey
     * @param processInstanceId 流程实例id
     * @param businessKey
     * @author zhonglj
     * @date 2024-10-09 9:03
     **/
    default void callReject(String processDefKey, String processInstanceId, String businessKey) {
        businessKey = getBusinessKey(processInstanceId, businessKey);
        updateApproveStatus(processInstanceId, businessKey, ApproveStatus.REJECT);
        reject(processDefKey, processInstanceId, businessKey);
    }

    /**
     * 驳回至提交人-业务逻辑覆盖
     *
     * @param processDefKey
     * @param processInstanceId 流程实例id
     * @param businessKey
     * @author zhonglj
     * @date 2024-10-09 9:03
     **/
    default void reject(String processDefKey, String processInstanceId, String businessKey) {
    }

    /**
     * 绑定流程定义码,默认使用DefaultActivityCallAbleImpl
     *
     * @param
     * @return com.wsoft.bpm.enums.BpmProcessDef
     * @author zhonglj
     * @date 2024-10-09 9:53
     **/
    String getProcessDefKey();

    /**
     * 同意前回调函数
     *
     * @param businessKey 业务唯一值
     * @param taskId      任务id
     * @param taskKey     任务节点id
     * @param taskName    任务名称
     * @return void
     * @author zhonglj
     * @date 2025/1/14 14:12
     **/
    default void beforeAgree(String businessKey, String taskId, String taskKey, String taskName) {
    }

    /**
     * 返回匹配的处理服务
     *
     * @param key 工作流唯一编码
     * @return com.wsoft.bpm.service.ActivityCallAble
     * @author zhonglj
     * @date 2024-10-09 9:09
     **/
    static ActivityCallAble findCallService(String key) {
        Map<String, ActivityCallAble> beansOfType = SpringUtil.getBeansOfType(ActivityCallAble.class);
        // 遍历匹配获取服务类
        int matchCount = 0;
        ActivityCallAble matchedCallAble = SpringUtil.getBean(DefaultActivityCallAbleImpl.class);
        for (ActivityCallAble callAble : beansOfType.values()) {
            if (StrUtil.equals(key, callAble.getProcessDefKey())) {
                matchedCallAble = callAble;
                matchCount++;
            }
        }

        if (matchCount > 1) {
            // 不允许多个匹配
            Asserts.fail("[bpm.process.error.findCallService.moreThanOne]");
        }

        return matchedCallAble;
    }

    /**
     * 更新数据库状态
     *
     * @param processInstanceId
     * @param businessKey
     * @param status
     * @return int
     * @author zhonglj
     * @date 2024-10-09 10:20
     **/
    static int updateApproveStatus(String processInstanceId, String businessKey, ApproveStatus status) {
        businessKey = getBusinessKey(processInstanceId, businessKey);
        BpmActivitiMapper mapper = SpringUtil.getBean(BpmActivitiMapper.class);
        IActProcessMappingService mappingService = SpringUtil.getBean(IActProcessMappingService.class);
        ActProcessMappingEntity processMapping = mappingService.getOne(Wrappers.lambdaQuery(ActProcessMappingEntity.class)
                .eq(ActProcessMappingEntity::getProcessInstantId, processInstanceId)
        );
        if (processMapping == null) {
            Asserts.fail("[bpm.process.error.updateApproveStatus.none.processMapping]");
        }

        return mapper.updateApproveStatus(
                processMapping.getTableName(),
                processMapping.getStatusColumn(),
                status.getValue(),
                processMapping.getBusinessKeyColumn(),
                businessKey
        );
    }

    static String getBusinessKey(String processInstanceId, String businessKey) {
        if (StrUtil.isNotBlank(businessKey)) {
            return businessKey;
        }

        HistoryService historyService = SpringUtil.getBean(HistoryService.class);
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();

        if (historicProcessInstance == null || StrUtil.isBlank(historicProcessInstance.getBusinessKey())) {
            Asserts.fail("[bpm.process.error.businessKey.empty]");
        }
        return historicProcessInstance.getBusinessKey();
    }
}
